"""
流水线处理模式
阶段1：快速批量处理（Tiny + Chat）
阶段2：智能升级重试（Base/Small + Reasoner）
"""

import logging
import time
import os
from typing import List, Dict, Optional
from core.transcriber import VideoTranscriber
from core.polish import TextPolisher
from utils.text_validator import check_text_quality
from client.api_client import APIClient

logger = logging.getLogger(__name__)


def convert_path(path: str, path_mapping: dict) -> str:
    """
    转换路径（Windows -> Mac/Linux）

    Args:
        path: 原始路径
        path_mapping: 路径映射字典

    Returns:
        转换后的路径
    """
    if not path or not path_mapping:
        return path

    # 替换反斜杠为正斜杠
    normalized_path = path.replace('\\', '/')

    # 尝试匹配并替换路径前缀
    for win_prefix, unix_prefix in path_mapping.items():
        # 标准化映射前缀
        win_prefix_normalized = win_prefix.replace('\\', '/')

        if normalized_path.startswith(win_prefix_normalized):
            # 替换前缀
            converted_path = normalized_path.replace(
                win_prefix_normalized, unix_prefix, 1
            )
            return converted_path

    return path


class PipelineProcessor:
    """流水线处理器"""

    def __init__(
        self,
        config: Dict,
        api_client: APIClient,
        transcriber: VideoTranscriber,
        polisher: TextPolisher
    ):
        self.config = config
        self.api_client = api_client
        self.transcriber = transcriber
        self.polisher = polisher
        self.batch_size = config.get('polish', {}).get('batch_size', 20)

    def _is_network_timeout(self, error_msg: str) -> bool:
        """
        检测错误是否为网络超时

        Args:
            error_msg: 错误信息

        Returns:
            True if 网络超时, False otherwise
        """
        if not error_msg:
            return False

        timeout_keywords = [
            'timeout', 'timed out', 'time out',
            'connection error', 'network error',
            'connection reset', 'read timeout',
            '超时', '网络错误', '连接失败', '连接重置'
        ]

        error_lower = str(error_msg).lower()
        return any(keyword in error_lower for keyword in timeout_keywords)

    def process(self, works: List[Dict], excel_path: str) -> Dict:
        """
        流水线处理

        Args:
            works: 作品列表
            excel_path: Excel文件路径（用于获取音频）

        Returns:
            统计结果
        """
        total = len(works)
        logger.info("=" * 60)
        logger.info("流水线模式启动")
        logger.info(f"总数: {total} 个作品")
        logger.info("=" * 60)

        # ============================================================
        # 阶段1：快速批量处理（Tiny + Chat）
        # ============================================================
        stage1_success, stage1_failed = self._stage1_fast_batch(works)

        logger.info("")
        logger.info("=" * 60)
        logger.info("阶段1完成")
        logger.info(f"✓ 成功: {len(stage1_success)}/{total} ({len(stage1_success)*100//total}%)")
        logger.info(f"✗ 失败: {len(stage1_failed)} (转录失败 + 润色失败)")
        logger.info("=" * 60)

        if len(stage1_failed) == 0:
            logger.info("所有作品处理成功，无需阶段2")
            return self._build_summary(stage1_success, [], [])

        # 等待5秒，可按 Ctrl+C 取消
        logger.info("")
        logger.info("准备进入阶段2（智能升级重试）...")
        logger.info("按 Ctrl+C 取消阶段2")
        try:
            for i in range(5, 0, -1):
                logger.info(f"等待 {i} 秒...")
                time.sleep(1)
        except KeyboardInterrupt:
            logger.info("\n用户取消阶段2")
            return self._build_summary(stage1_success, [], stage1_failed)

        # ============================================================
        # 阶段2：智能升级重试（Base/Small + Reasoner）
        # ============================================================
        stage2_success, stage2_failed = self._stage2_smart_retry(stage1_failed)

        logger.info("")
        logger.info("=" * 60)
        logger.info("阶段2完成")
        logger.info(f"✓ 恢复成功: {len(stage2_success)}/{len(stage1_failed)}")
        logger.info(f"✗ 最终失败: {len(stage2_failed)}")
        logger.info("=" * 60)

        # 返回总体统计
        return self._build_summary(stage1_success, stage2_success, stage2_failed)

    def _stage1_fast_batch(self, works: List[Dict]) -> tuple:
        """
        阶段1：快速批量处理

        Returns:
            (成功列表, 失败列表)
        """
        logger.info("")
        logger.info("开始阶段1：快速批量处理")
        logger.info("模型: Whisper Tiny + DeepSeek Chat")
        logger.info("")

        success_list = []
        failed_list = []
        upload_buffer = []

        total = len(works)

        for idx, work in enumerate(works, 1):
            try:
                work_id = work.get('workId', work.get('id'))
                title = work.get('title', 'N/A')
                safe_title = self._safe_text(title)

                logger.info(f"[{idx}/{total}] {work_id} - {safe_title}")

                # 跳过非视频
                if work.get('workType') != 0:
                    logger.info(f"  └─ ⊘ 跳过非视频作品")
                    continue

                # 步骤1：转录（使用 Tiny 模型）
                raw_text = work.get('rawText', '')
                is_pure_music = False

                # 获取音频路径（从 savePath）
                # 默认启用路径代理：只要有 savePath 就尝试转换，不检查 isDownloaded
                audio_path = None
                if work.get('savePath'):
                    path_mapping = self.config.get('worker', {}).get('path_mapping', {})
                    original_path = work['savePath']
                    audio_path = convert_path(original_path, path_mapping)
                    logger.info(f"  ├─ 路径转换: {original_path[:50]}... → {audio_path[:50] if audio_path else 'None'}...")

                    if not os.path.exists(audio_path):
                        logger.warning(f"  ├─ ✗ 音频文件不存在: {audio_path}")
                        audio_path = None
                    else:
                        logger.info(f"  ├─ ✓ 音频文件存在")

                if audio_path:
                    logger.info(f"  ├─ 转录音频 (Tiny)")
                    try:
                        result = self.transcriber.transcribe(audio_path, language='zh')
                        raw_text = result.get('text', '')

                        # 打印转录结果
                        if raw_text:
                            text_len = len(raw_text)
                            if text_len <= 200:
                                logger.info(f"  ├─ 转录内容({text_len}字): {raw_text}")
                            else:
                                logger.info(f"  ├─ 转录内容({text_len}字):")
                                logger.info(f"      前100字: {raw_text[:100]}")
                                logger.info(f"      后100字: {raw_text[-100:]}")
                        else:
                            logger.warning(f"  ├─ 转录结果为空！")

                        # 纯音乐检测
                        is_pure_music = self._is_pure_music(raw_text)
                        if is_pure_music:
                            logger.info(f"  ├─ 检测到纯音乐视频，标记为 [纯音乐]")
                            raw_text = "[纯音乐]"

                    except Exception as e:
                        logger.error(f"  ├─ 转录异常: {str(e)}")
                        # 转录异常，上传失败记录
                        upload_buffer.append({
                            'platform': work['platform'],
                            'workId': work_id,
                            'databaseId': work.get('databaseId'),
                            'rawText': '',
                            # 新字段
                            'status': 'failed',
                            'lastAttemptModel': 'tiny',
                            'failureReason': 'transcribe_error',
                            'retryCount': 1,
                            # 旧字段（向后兼容）
                            'transcribeStatus': 'failed',
                            'transcribeModel': 'tiny',
                            'transcribeFailedReason': str(e),
                            'polishStatus': 3,
                        })
                        failed_list.append({
                            'work': work,
                            'reason': 'transcribe_error',
                            'error': str(e),
                            'audio_path': audio_path
                        })
                        self._batch_upload(upload_buffer, force=False)
                        continue
                else:
                    logger.warning(f"  ├─ 跳过转录：无可用音频文件")

                # 步骤2：质量检测（跳过纯音乐）
                quality = check_text_quality(raw_text)
                if not quality['is_valid'] and not is_pure_music:
                    logger.warning(f"  ├─ 质量检测失败: {quality['reason']}")
                    logger.info("  └─ ✗ 转录失败（质量不合格）")

                    # 上传转录失败记录
                    upload_buffer.append({
                        'platform': work['platform'],
                        'workId': work_id,
                        'databaseId': work.get('databaseId'),
                        'rawText': raw_text,
                        # 新字段
                        'status': 'failed',
                        'lastAttemptModel': 'tiny',
                        'failureReason': 'transcribe_quality',
                        'retryCount': 1,
                        # 旧字段（向后兼容）
                        'transcribeStatus': 'failed',  # 阶段1标记失败
                        'transcribeModel': 'tiny',
                        'transcribeFailedReason': quality['reason'],
                        'polishStatus': 3,  # 3 = 转录异常，跳过润色
                    })

                    failed_list.append({
                        'work': work,
                        'reason': 'transcribe_failed',
                        'quality': quality,
                        'raw_text': raw_text
                    })

                    self._batch_upload(upload_buffer, force=False)
                    continue

                # 步骤3：润色（跳过纯音乐）
                if is_pure_music:
                    logger.info("  └─ ⊘ 纯音乐，跳过润色")
                    upload_buffer.append({
                        'platform': work['platform'],
                        'workId': work_id,
                        'databaseId': work.get('databaseId'),
                        'rawText': raw_text,
                        # 新字段
                        'status': 'completed',
                        'lastAttemptModel': 'tiny',
                        'failureReason': None,
                        'retryCount': 0,
                        # 旧字段（向后兼容）
                        'transcribeStatus': 'success',
                        'transcribeModel': 'tiny',
                        'polishedText': '[纯音乐]',
                        'polishStatus': 1,
                        'polishEngine': None,
                    })
                    success_list.append({
                        'work': work,
                        'transcribe_model': 'tiny',
                        'polish_model': None,
                        'is_pure_music': True
                    })
                    self._batch_upload(upload_buffer, force=False)
                    continue

                logger.info("  ├─ 润色 (Chat)")
                context = {
                    'title': work.get('title'),
                    'author': work.get('author'),
                    'platform': work.get('platform'),
                }

                polish_result = self.polisher.polish(raw_text, context, model='deepseek-chat')

                if polish_result['status'] == 1:
                    # 成功
                    polished_text = polish_result['polished_text']
                    logger.info(f"  ├─ ✓ 润色成功 (评分: {polish_result.get('quality_score')})")

                    # 打印润色结果
                    if polished_text:
                        text_len = len(polished_text)
                        if text_len <= 200:
                            logger.info(f"  ├─ 润色内容({text_len}字): {polished_text}")
                        else:
                            logger.info(f"  ├─ 润色内容({text_len}字):")
                            logger.info(f"      前100字: {polished_text[:100]}")
                            logger.info(f"      后100字: {polished_text[-100:]}")
                    else:
                        logger.warning(f"  ├─ 润色结果为空！")

                    logger.info(f"  └─ 准备上传")

                    upload_buffer.append({
                        'platform': work['platform'],
                        'workId': work_id,
                        'databaseId': work.get('databaseId'),
                        'rawText': raw_text,
                        # 新字段
                        'status': 'completed',
                        'lastAttemptModel': 'chat',
                        'failureReason': None,
                        'retryCount': 1,
                        'qualityScore': polish_result.get('quality_score'),
                        # 旧字段（向后兼容）
                        'transcribeStatus': 'success',
                        'transcribeModel': 'tiny',
                        'polishedText': polished_text,
                        'polishStatus': 1,
                        'polishEngine': 'deepseek-chat',
                    })

                    success_list.append({
                        'work': work,
                        'transcribe_model': 'tiny',
                        'polish_model': 'deepseek-chat',
                        'quality_score': polish_result.get('quality_score')
                    })
                else:
                    # 润色失败，判断原因
                    error_msg = polish_result.get('error', '')
                    is_network = self._is_network_timeout(error_msg)

                    if is_network:
                        # 网络超时，标记为重试
                        logger.warning(f"  └─ ✗ 润色网络超时，将在 Stage 2 重试")
                        upload_buffer.append({
                            'platform': work['platform'],
                            'workId': work_id,
                            'databaseId': work.get('databaseId'),
                            'rawText': raw_text,
                            # 新字段
                            'status': 'polishing',
                            'lastAttemptModel': 'chat',
                            'failureReason': 'polish_network_timeout',
                            'retryCount': 1,
                            # 旧字段（向后兼容）
                            'transcribeStatus': 'success',
                            'transcribeModel': 'tiny',
                            'polishedText': '',
                            'polishStatus': 2,  # 阶段1失败
                            'polishEngine': 'deepseek-chat',
                            'polishFailedReason': error_msg,
                            'qualityScore': 0,
                        })
                    else:
                        # 内容问题，需要升级转录
                        logger.warning(f"  └─ ✗ 润色内容问题: {error_msg}")
                        upload_buffer.append({
                            'platform': work['platform'],
                            'workId': work_id,
                            'databaseId': work.get('databaseId'),
                            'rawText': raw_text,
                            # 新字段
                            'status': 'polish_pending',
                            'lastAttemptModel': 'chat',
                            'failureReason': 'polish_content_invalid',
                            'retryCount': 1,
                            # 旧字段（向后兼容）
                            'transcribeStatus': 'success',
                            'transcribeModel': 'tiny',
                            'polishedText': '',
                            'polishStatus': 2,  # 阶段1失败
                            'polishEngine': 'deepseek-chat',
                            'polishFailedReason': error_msg,
                            'qualityScore': 0,
                        })

                    # 加入失败列表
                    failed_list.append({
                        'work': work,
                        'reason': 'polish_failed',
                        'raw_text': raw_text,
                        'error': error_msg,
                        'is_network_timeout': is_network,
                    })

                self._batch_upload(upload_buffer, force=False)

            except Exception as e:
                logger.error(f"  └─ ✗ 处理异常: {str(e)}")
                failed_list.append({
                    'work': work,
                    'reason': 'exception',
                    'error': str(e)
                })

        # 上传剩余数据
        self._batch_upload(upload_buffer, force=True)

        return success_list, failed_list

    def _stage2_smart_retry(self, failed_list: List[Dict]) -> tuple:
        """
        阶段2：智能升级重试

        Args:
            failed_list: 阶段1失败的列表

        Returns:
            (成功列表, 最终失败列表)
        """
        logger.info("")
        logger.info("开始阶段2：智能升级重试")
        logger.info("模型升级路径: Tiny→Base→Small, Chat→Reasoner")
        logger.info("")

        success_list = []
        final_failed = []
        upload_buffer = []

        total = len(failed_list)

        for idx, failed_item in enumerate(failed_list, 1):
            work = failed_item['work']
            reason = failed_item['reason']
            work_id = work.get('workId', work.get('id'))
            title = work.get('title', 'N/A')
            safe_title = self._safe_text(title)

            logger.info(f"[{idx}/{total}] {work_id} - {safe_title}")
            logger.info(f"  ├─ 阶段1失败原因: {reason}")

            if reason == 'transcribe_failed':
                # 转录失败 → 升级 Whisper 模型
                result = self._upgrade_transcribe(work, failed_item)

                if result['success']:
                    upload_buffer.append(result['data'])
                    success_list.append(result['summary'])
                else:
                    upload_buffer.append(result['data'])
                    final_failed.append(failed_item)

            elif reason == 'polish_failed':
                # 润色失败 → 升级润色模型
                result = self._upgrade_polish(work, failed_item)

                if result['success']:
                    upload_buffer.append(result['data'])
                    success_list.append(result['summary'])
                else:
                    upload_buffer.append(result['data'])
                    final_failed.append(failed_item)

            self._batch_upload(upload_buffer, force=False)

        # 上传剩余数据
        self._batch_upload(upload_buffer, force=True)

        return success_list, final_failed

    def _upgrade_transcribe(self, work: Dict, failed_item: Dict) -> Dict:
        """
        升级转录模型: Tiny → Base → Small

        Returns:
            {
                'success': bool,
                'data': {...},  # 上传数据
                'summary': {...}  # 统计数据
            }
        """
        work_id = work.get('workId', work.get('id'))

        # 获取音频路径（从 savePath）
        # 默认启用路径代理：只要有 savePath 就尝试转换，不检查 isDownloaded
        audio_path = None
        if work.get('savePath'):
            path_mapping = self.config.get('worker', {}).get('path_mapping', {})
            original_path = work['savePath']
            audio_path = convert_path(original_path, path_mapping)

        if not audio_path or not os.path.exists(audio_path):
            logger.error(f"  └─ ✗ 无音频文件，无法重新转录 (path: {audio_path or 'None'})")
            return {
                'success': False,
                'data': {
                    'platform': work['platform'],
                    'workId': work_id,
                    'databaseId': work.get('databaseId'),
                    # 新字段
                    'status': 'failed',
                    'lastAttemptModel': 'tiny',
                    'failureReason': 'transcribe_error',
                    'retryCount': 1,
                    # 旧字段（向后兼容）
                    'transcribeStatus': 'failed',
                    'transcribeModel': 'tiny',
                    'transcribeFailedModel': 'tiny',
                    'transcribeFailedReason': '无音频文件',
                    'polishStatus': 0,
                },
                'summary': {}
            }

        # 尝试 Base 和 Small
        for model in ['base', 'small']:
            logger.info(f"  ├─ 尝试 {model.capitalize()} 模型转录")

            try:
                # 创建临时的高级模型转录器
                from core.transcriber import VideoTranscriber
                temp_config = {
                    'model': {
                        'name': model,
                        'device': self.config.get('transcription', {}).get('device', 'auto'),
                        'compute_type': self.config.get('transcription', {}).get('compute_type', 'auto')
                    },
                    'output': {
                        'dir': './output',
                        'formats': []
                    }
                }
                temp_transcriber = VideoTranscriber(temp_config)

                result = temp_transcriber.transcribe(audio_path, language='zh')
                raw_text = result.get('text', '')

                # 纯音乐检测
                is_pure_music = self._is_pure_music(raw_text)
                if is_pure_music:
                    logger.info(f"  ├─ 检测到纯音乐视频，标记为 [纯音乐]")
                    raw_text = "[纯音乐]"

                # 质量检测（跳过纯音乐）
                quality = check_text_quality(raw_text)

                if not quality['is_valid'] and not is_pure_music:
                    logger.warning(f"  ├─ {model.capitalize()} 质量不合格: {quality['reason']}")
                    continue

                logger.info(f"  ├─ {model.capitalize()} 转录成功")

                # 转录成功，尝试润色（或跳过纯音乐）
                if is_pure_music:
                    logger.info(f"  └─ ⊘ 纯音乐，跳过润色")
                    return {
                        'success': True,
                        'data': {
                            'platform': work['platform'],
                            'workId': work_id,
                            'databaseId': work.get('databaseId'),
                            'rawText': raw_text,
                            # 新字段
                            'status': 'completed',
                            'lastAttemptModel': model,
                            'failureReason': None,
                            'retryCount': 0,
                            # 旧字段（向后兼容）
                            'transcribeStatus': 'success',
                            'transcribeModel': model,
                            'polishedText': '[纯音乐]',
                            'polishStatus': 1,
                            'polishEngine': None,
                        },
                        'summary': {'work': work, 'transcribe_model': model, 'polish_model': None, 'is_pure_music': True}
                    }

                return self._try_polish_with_upgrade(work, raw_text, model)

            except Exception as e:
                logger.error(f"  ├─ {model.capitalize()} 转录异常: {str(e)}")
                continue

        # 所有模型都失败
        logger.error("  └─ ✗ 所有转录模型都失败（Tiny→Base→Small）")
        return {
            'success': False,
            'data': {
                'platform': work['platform'],
                'workId': work_id,
                'databaseId': work.get('databaseId'),
                # 新字段
                'status': 'failed',
                'lastAttemptModel': 'small',
                'failureReason': 'max_transcribe_attempts',
                'retryCount': 3,  # tiny + base + small
                # 旧字段（向后兼容）
                'transcribeStatus': 'failed',
                'transcribeModel': 'small',
                'transcribeFailedModel': 'small',
                'transcribeFailedReason': '尝试所有模型均失败: tiny→base→small',
                'polishStatus': 0,
            },
            'summary': {}
        }

    def _upgrade_polish(self, work: Dict, failed_item: Dict) -> Dict:
        """
        升级润色模型: Chat → Reasoner

        Returns:
            同 _upgrade_transcribe
        """
        work_id = work.get('workId', work.get('id'))
        raw_text = failed_item.get('raw_text', '')

        logger.info("  ├─ 尝试 Reasoner 模型润色")

        context = {
            'title': work.get('title'),
            'author': work.get('author'),
            'platform': work.get('platform'),
        }

        polish_result = self.polisher.polish(raw_text, context, model='deepseek-reasoner')

        if polish_result['status'] == 1:
            logger.info(f"  └─ ✓ Reasoner 润色成功 (评分: {polish_result.get('quality_score')})")
            return {
                'success': True,
                'data': {
                    'platform': work['platform'],
                    'workId': work_id,
                    'databaseId': work.get('databaseId'),
                    # 新字段
                    'status': 'completed',
                    'lastAttemptModel': 'reasoner',
                    'failureReason': None,
                    'retryCount': 2,  # chat + reasoner
                    'qualityScore': polish_result.get('quality_score'),
                    # 旧字段（向后兼容）
                    'polishedText': polish_result['polished_text'],
                    'polishStatus': 1,
                    'polishEngine': 'deepseek-reasoner',
                },
                'summary': {
                    'work': work,
                    'polish_model': 'deepseek-reasoner',
                    'quality_score': polish_result.get('quality_score')
                }
            }
        else:
            # Reasoner 也失败
            logger.error(f"  └─ ✗ Reasoner 润色失败: {polish_result.get('error')}")
            self._log_final_failure(work, raw_text, polish_result)

            return {
                'success': False,
                'data': {
                    'platform': work['platform'],
                    'workId': work_id,
                    'databaseId': work.get('databaseId'),
                    # 新字段
                    'status': 'failed',
                    'lastAttemptModel': 'reasoner',
                    'failureReason': 'polish_max_retries',
                    'retryCount': 2,  # chat + reasoner
                    # 旧字段（向后兼容）
                    'polishStatus': 2,
                    'polishEngine': 'deepseek-reasoner',
                    'polishFailedModel': 'deepseek-reasoner',
                    'polishFailedReason': f'尝试所有模型均失败: {polish_result.get("error")}',
                    'qualityScore': 0,
                },
                'summary': {}
            }

    def _try_polish_with_upgrade(self, work: Dict, raw_text: str, transcribe_model: str) -> Dict:
        """转录成功后，尝试润色（Chat → Reasoner）"""
        work_id = work.get('workId', work.get('id'))
        context = {
            'title': work.get('title'),
            'author': work.get('author'),
            'platform': work.get('platform'),
        }

        # 尝试 Chat
        logger.info("  ├─ 润色 (Chat)")
        polish_result = self.polisher.polish(raw_text, context, model='deepseek-chat')

        if polish_result['status'] == 1:
            logger.info(f"  └─ ✓ 成功 (评分: {polish_result.get('quality_score')})")
            return {
                'success': True,
                'data': {
                    'platform': work['platform'],
                    'workId': work_id,
                    'databaseId': work.get('databaseId'),
                    'rawText': raw_text,
                    # 新字段
                    'status': 'completed',
                    'lastAttemptModel': 'chat',
                    'failureReason': None,
                    'retryCount': 1,
                    'qualityScore': polish_result.get('quality_score'),
                    # 旧字段（向后兼容）
                    'transcribeStatus': 'success',
                    'transcribeModel': transcribe_model,
                    'polishedText': polish_result['polished_text'],
                    'polishStatus': 1,
                    'polishEngine': 'deepseek-chat',
                },
                'summary': {
                    'work': work,
                    'transcribe_model': transcribe_model,
                    'polish_model': 'deepseek-chat',
                    'quality_score': polish_result.get('quality_score')
                }
            }

        # Chat 失败，尝试 Reasoner
        logger.warning(f"  ├─ Chat 失败: {polish_result.get('error')}")
        logger.info("  ├─ 润色 (Reasoner)")

        polish_result = self.polisher.polish(raw_text, context, model='deepseek-reasoner')

        if polish_result['status'] == 1:
            logger.info(f"  └─ ✓ Reasoner 成功 (评分: {polish_result.get('quality_score')})")
            return {
                'success': True,
                'data': {
                    'platform': work['platform'],
                    'workId': work_id,
                    'databaseId': work.get('databaseId'),
                    'rawText': raw_text,
                    # 新字段
                    'status': 'completed',
                    'lastAttemptModel': 'reasoner',
                    'failureReason': None,
                    'retryCount': 2,  # chat + reasoner
                    'qualityScore': polish_result.get('quality_score'),
                    # 旧字段（向后兼容）
                    'transcribeStatus': 'success',
                    'transcribeModel': transcribe_model,
                    'polishedText': polish_result['polished_text'],
                    'polishStatus': 1,
                    'polishEngine': 'deepseek-reasoner',
                },
                'summary': {
                    'work': work,
                    'transcribe_model': transcribe_model,
                    'polish_model': 'deepseek-reasoner',
                    'quality_score': polish_result.get('quality_score')
                }
            }

        # 所有润色都失败
        logger.error(f"  └─ ✗ Reasoner 也失败: {polish_result.get('error')}")
        self._log_final_failure(work, raw_text, polish_result)

        return {
            'success': False,
            'data': {
                'platform': work['platform'],
                'workId': work_id,
                'databaseId': work.get('databaseId'),
                'rawText': raw_text,
                # 新字段
                'status': 'failed',
                'lastAttemptModel': 'reasoner',
                'failureReason': 'polish_max_retries',
                'retryCount': 2,  # chat + reasoner
                # 旧字段（向后兼容）
                'transcribeStatus': 'success',
                'transcribeModel': transcribe_model,
                'polishStatus': 2,
                'polishEngine': 'deepseek-reasoner',
                'polishFailedModel': 'deepseek-reasoner',
                'polishFailedReason': f'尝试所有润色模型均失败: {polish_result.get("error")}',
                'qualityScore': 0,
            },
            'summary': {}
        }

    def _log_final_failure(self, work: Dict, raw_text: str, polish_result: Dict):
        """记录最终失败的详细信息"""
        logger.error("")
        logger.error("=" * 80)
        logger.error("所有模型均失败 - 详细信息")
        logger.error("=" * 80)
        logger.error(f"Work ID: {work.get('workId', work.get('id'))}")
        logger.error(f"标题: {work.get('title', 'N/A')}")
        logger.error("-" * 80)
        logger.error(f"传入文本长度: {len(raw_text)} 字符")
        logger.error(f"传入文本(前500字符):")
        logger.error(raw_text[:500] if raw_text else "N/A")
        logger.error("-" * 80)
        logger.error(f"最后错误: {polish_result.get('error')}")
        api_resp = polish_result.get('api_response')
        if api_resp:
            logger.error(f"API响应(前500字符):")
            logger.error(str(api_resp)[:500] if api_resp else "N/A")
        logger.error("=" * 80)
        logger.error("")

    def _batch_upload(self, buffer: List[Dict], force: bool = False):
        """批量上传"""
        if force or len(buffer) >= self.batch_size:
            if len(buffer) > 0:
                logger.info(f">>> 批量上传 {len(buffer)} 条...")

                # 打印完整的上传数据（用于调试）
                if buffer:
                    import json
                    logger.info(f">>> 上传数据详情:")
                    logger.info(json.dumps(buffer[0], ensure_ascii=False, indent=2))

                result = self.api_client.batch_update_polish(buffer)
                if result.get('success'):
                    updated = result.get('updated', 0)
                    failed = result.get('failed', 0)
                    logger.info(f">>> 上传成功: {updated} 条, 失败: {failed} 条")

                    # 如果有失败，打印失败信息
                    if failed > 0:
                        logger.error(f">>> 上传部分失败！请检查后台日志")
                else:
                    logger.error(f">>> 上传失败: {result.get('message')}")
                buffer.clear()

    def _safe_text(self, text: str, max_len: int = 50) -> str:
        """安全处理文本（避免编码错误）"""
        if not text:
            return 'N/A'
        import sys
        if sys.platform == 'win32':
            import re
            text = re.sub(r'[^\u4e00-\u9fa5\u3000-\u303fa-zA-Z0-9\s\-_,;.!?()（）【】《》""''：；，。！？]', '', text)
        return text[:max_len] + ('...' if len(text) > max_len else '')

    def _is_pure_music(self, text: str) -> bool:
        """
        检测文本是否为纯音乐（无有效人声内容）

        Args:
            text: 转录文本

        Returns:
            True 如果是纯音乐，False 否则
        """
        if not text or not text.strip():
            return True

        # 去除空白字符
        text = text.strip()

        # 如果文本太短（少于10个字符），可能是纯音乐
        if len(text) < 10:
            return True

        # 计算有效中文字符占比
        chinese_chars = sum(1 for c in text if '\u4e00' <= c <= '\u9fff')
        total_chars = len(text.replace(' ', '').replace('\n', ''))

        if total_chars == 0:
            return True

        chinese_ratio = chinese_chars / total_chars

        # 如果中文字符占比低于20%，且文本主要是字母/符号，可能是音乐识别噪音
        if chinese_ratio < 0.2 and total_chars > 50:
            # 检查是否主要是单字母或短词（音乐识别特征）
            words = text.replace('-', ' ').split()
            short_words = sum(1 for w in words if len(w) <= 3)
            if len(words) > 0 and short_words / len(words) > 0.8:
                return True

        return False

    def _build_summary(self, stage1_success: List, stage2_success: List, final_failed: List) -> Dict:
        """构建总体统计"""
        total = len(stage1_success) + len(stage2_success) + len(final_failed)

        logger.info("")
        logger.info("=" * 60)
        logger.info("流水线处理完成 - 总体统计")
        logger.info("=" * 60)
        logger.info(f"总数: {total}")
        logger.info(f"✓ 阶段1成功: {len(stage1_success)}")
        logger.info(f"✓ 阶段2恢复: {len(stage2_success)}")
        logger.info(f"✓ 总成功: {len(stage1_success) + len(stage2_success)} ({(len(stage1_success)+len(stage2_success))*100//total}%)")
        logger.info(f"✗ 最终失败: {len(final_failed)} ({len(final_failed)*100//total}%)")
        logger.info("=" * 60)

        return {
            'total': total,
            'stage1_success': len(stage1_success),
            'stage2_success': len(stage2_success),
            'final_failed': len(final_failed),
            'success_rate': (len(stage1_success) + len(stage2_success)) / total if total > 0 else 0
        }
